import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import model.Article;
import model.ArticleImpl;
import model.Author;
import model.AuthorImpl;
import model.Comment;
import model.CommentImpl;
import model.Discussion;
import model.DiscussionImpl;

public class Parser {

	private final String COMMENT_DELIMITATOR_REGEX = "\\(UTC\\)";
	private final String FILE_EXTENSION = ".txt";
	private final String FILENAME_PREFIX = "Talk_";

	private String filename;

	public Parser(String filename) {
		this.filename = filename;
	}

	public Article parseArticle() throws IOException {
		Article article = new ArticleImpl();

		boolean hasDiscussionStarted = false;
		boolean isCommentDelimiterDetected = false;
		boolean isCommentReply = false;
		boolean didPrevCommentHasCommentDelimiterDetected = false;
		int replyLevel = 1;
		Author author = null;
		Comment replyComment = null;
		Comment comment = null;
		Discussion discussion = null;
		Map<Integer, Comment> commentLevels = new HashMap<Integer, Comment>();
		String articleName = null;
		String currentLine = null;
		String date = null;
		String[] splittedLine = null;

		// Assume that all files for now will be in the same format:
		// Talk_<ARTICLE_NAME_ON_WIKIPEDIA>.txt
		articleName = filename.replace(FILENAME_PREFIX, "").replace(
				FILE_EXTENSION, "");

		article.setName(articleName);

		BufferedReader br = new BufferedReader(new FileReader(filename));

		while ((currentLine = br.readLine()) != null) {
			isCommentDelimiterDetected = (currentLine.contains("(UTC)"));

			// Discussion has started and we have at least one comment,
			// assume that this is a new discussion starting now
			if (hasDiscussionStarted
					&& didPrevCommentHasCommentDelimiterDetected
					&& discussion != null
					&& discussion.getComments().size() > 0) {
				didPrevCommentHasCommentDelimiterDetected = false;
				hasDiscussionStarted = false;
			}

			if (!isCommentDelimiterDetected && !hasDiscussionStarted) {
				discussion = new DiscussionImpl();
				discussion.setTitle(currentLine);
				article.addDiscussion(discussion);

				hasDiscussionStarted = true;
			} else {
				splittedLine = currentLine.split(COMMENT_DELIMITATOR_REGEX);

				if (splittedLine.length > 0) {

					if (splittedLine.length == 2 && splittedLine[1].equals(" ")) {
						++replyLevel;
						isCommentReply = true;
					} else {
						--replyLevel;
						isCommentReply = false;
					}

					author = new AuthorImpl();

					// Assume that "." can't be used in the user name
					int pos = currentLine.lastIndexOf(".") + 1;
					if (isCommentDelimiterDetected && pos != -1 && pos < currentLine.length()) {
						String strUserPart = currentLine.substring(pos,
								currentLine.length());

						if (strUserPart.charAt(0) == ' ') {
							strUserPart = strUserPart.substring(1,
									strUserPart.length());
						}

						if (strUserPart != null && !strUserPart.equals("")) {
							String[] userParts = strUserPart.split(" ");

							if (userParts.length >= 7) {
								String username = userParts[0];
								String talk = userParts[1];
								String time = userParts[2];
								String day = userParts[3];
								String month = userParts[4];
								String year = userParts[5];
								String utc = userParts[6];

								date = time + " " + day + " " + month + " "
										+ year + " " + utc;
								author.setUsername(username);
							}
						}
					}

					if (isCommentReply) {
						replyComment = addChildCommentToComment(comment,
								article, author, date, splittedLine[0]);
						commentLevels.put(replyLevel, replyComment);
					} else {
						comment = createComment(article, author, date,
								splittedLine[0]);
						addCommentToDiscussion(discussion, comment);
						commentLevels.put(replyLevel, comment);
					}

					date = null;
				}
			}

			didPrevCommentHasCommentDelimiterDetected = isCommentDelimiterDetected;
		}

		br.close();

		return article;
	}

	private Comment addChildCommentToComment(Comment parentComment,
			Article article, Author author, String date, String text) {
		Comment childComment = null;

		if (parentComment != null) {
			childComment = createComment(article, author, date, text);
			parentComment.addChildComment(childComment);
		}

		return childComment;
	}

	private Comment addCommentToDiscussion(Discussion discussion,
			Comment comment) {
		if (discussion != null && comment != null) {
			discussion.addComment(comment);
		}

		return comment;
	}

	private Comment createComment(Article article, Author author, String date,
			String text) {
		Comment comment = new CommentImpl();
		comment.setArticle(article);
		comment.setAuthor(author);
		comment.setDate(date);
		comment.setText(text);

		return comment;
	}

	private void updateAuthorLinkBetweenComments(Article a) {
		for (Discussion d : a.getDiscussions()) {
			for (Comment c : d.getComments()) {
				if (c.getAuthor() != null) {
					String username = c.getAuthor().getUsername();
					if (username == null || username.equals("")) {
						updateCommentLinks(c);
					}
				}
			}
		}
	}

	private void updateCommentLinks(Comment pc) {
		for (Comment cc : pc.getChildComments()) {
			updateCommentLinks(cc);

			if (pc.getAuthor() != null) {
				String username = pc.getAuthor().getUsername();

				if (username == null || username.equals("")) {
					updateCommentLinks(cc);

					if (cc.getAuthor() != null) {
						String childUsername = cc.getAuthor().getUsername();
						if (childUsername != null && !childUsername.equals("")) {
							pc.setAuthor(cc.getAuthor());
						}
					}
				}
			}
		}
	}

}
